/**
 * Copyright (C) 2009+ Spark Zheng
 *
 * @file        src/protocols/def_tcp/def_tcp.c 
 * @date        2010-04-22
 * @brief	protocol_module
 * @see         dserver
 * @history
 */

#include <dlib/str.h>
#include <dlib/mempool.h>
#include <dlib/buffer.h>
#include <dlib/confloose.h>

#include "dserver.h"
#include "dserver_errno.h"
#include "dserver_log.h"
#include "def_tcp.h"

int protocol_on_load(const void *settings, prot_node_t *prot)
{
	char *str;
	dlib_confl_t *confl;

	DLOG_DEBUG(LOG_PROT, "PROTOCOL(TCP): protocol_on_load.");

	if (settings == NULL || prot == NULL) {
		DLOG_ERR(LOG_PROT, "protocol_on_load parameters error.");
		return -E_ARGS_ILLEGAL;
	}
	confl = ((const dserver_setting_t *)settings)->dserver_confl;

	str = dlib_confl_get_string(confl, prot->p_name, "data", CONFL_STR_MOVE);
	if (str != NULL) {
		prot->p_data = str;
	} else {
		prot->p_data = strdup("def_tcp:test data in default");
	}

	return PROTOCOL_SUCCESS;
}

int protocol_session_init(void *arg)
{
	DLOG_DEBUG(LOG_PROT, "PROTOCOL(TCP): protocol_session_init.");

	if (arg == NULL) {
		DLOG_ERR(LOG_PROT, "protocol_session_init parameters error.");
		return -E_ARGS_ILLEGAL;
	}

	dserver_conn_t *conn = (dserver_conn_t *)arg;
	prot_node_t *prot = conn->c_prot_node;
	char client_ip[INET_ADDRSTRLEN] = {0};

	ipv4_to_str(((struct sockaddr_in *)(&conn->c_csa))->sin_addr.s_addr, client_ip);
	DLOG_INFO(LOG_PROT, "session_init: load data: %s | client info: %s",
			(char *)prot->p_data, client_ip);

	return PROTOCOL_SUCCESS;
}

prot_ret_t protocol_session_worker(void *arg)
{
	pipeline_data_t pdata;

	DLOG_DEBUG(LOG_PROT, "PROTOCOL(TCP): protocol_session_worker.");

	if (arg == NULL) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker parameters error.");
		return PROTOCOL_ERROR;
	}

	dserver_conn_t *conn = (dserver_conn_t *)arg;

	if (conn->c_rsize == 0) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker received data error.");
		return PROTOCOL_ERROR;
	}
	
	/* sendback data to socket directively */
	/*
	prot_node_t *prot = conn->c_prot_node;

	size_t global_data_len = strlen((char *)prot->p_data) + 1;
	conn->c_wsize = conn->c_rsize + global_data_len;
	snprintf(conn->c_wbuf, DSERVER_TX_BUFLEN, "%s:%s", (char *)prot->p_data, conn->c_rbuf);

	DLOG_DEBUG(LOG_PROT, "protocol_session_worker sending data[%s].", conn->c_wbuf);

	if (dserver_tcp_data_sendout(conn) < 0) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker sending data error.");
		return PROTOCOL_ERROR;
	}
	*/

	filter_node_t *filter = filter_get_by_name("test_1");
	if (filter == NULL) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker get filter error.");
		return PROTOCOL_ERROR;
	} else {
		DLOG_DEBUG(LOG_PROT, "protocol_session_worker get filter[%p].", filter);
	}
	pipeline_node_t *pipeline = pipeline_get_by_name("test_1");
	if (pipeline == NULL) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker get pipeline error.");
		return PROTOCOL_ERROR;
	} else {
		DLOG_DEBUG(LOG_PROT, "protocol_session_worker get pipeline[%p].", pipeline);
	}

	/* pass data to the pipeline */
	conn->c_data = (void *)dlib_buffer_init(16);
	pipeline_data_setup(&pdata);
	pdata.p_data = (void *)conn;

#ifdef DEF_TCP_IGNORE
	/* pass conn struct to filter */
	pdata.p_prot_flag = PROT_PIPELINE_IGNORE;
	int ret = pipeline_request(pipeline, filter, &pdata);
	if (ret < 0) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker pass data to pipeline error[%d].", ret);
		pipeline_data_cleanup(&pdata);
		dlib_buffer_exit((dlib_buffer_t *)(conn->c_data));
		conn->c_data = NULL;
		return PROTOCOL_ERROR;
	} else {
		DLOG_DEBUG(LOG_PROT, "protocol_session_worker pass data success.");
	}

#if 0
	/* will block until pipeline_result returns data */
	ret = pipeline_result(&pdata);
	if (ret < 0) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker retrieve data from pipeline error.");
		pipeline_data_cleanup(&pdata);
		dlib_buffer_exit((dlib_buffer_t *)(conn->c_data));
		conn->c_data = NULL;
		return PROTOCOL_ERROR;
	} else {
		DLOG_DEBUG(LOG_PROT, "protocol_session_worker retrieve data success.");
	}
#else
	/* just return and ignore connection */
	pipeline_data_cleanup(&pdata);
	dlib_buffer_exit((dlib_buffer_t *)(conn->c_data));
	conn->c_data = NULL;
	return PROTOCOL_IGNORE;
#endif
#else
	/* will block until pipeline_dispatch returns data */
	int ret = pipeline_dispatch(pipeline, filter, &pdata);
	if (ret < 0) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker dispatch pipeline error[%d].", ret);
		pipeline_data_cleanup(&pdata);
		dlib_buffer_exit((dlib_buffer_t *)(conn->c_data));
		conn->c_data = NULL;
		return PROTOCOL_ERROR;
	} else {
		DLOG_DEBUG(LOG_PROT, "protocol_session_worker pass data success.");
	}
#endif

	/* use conn->c_data, pass data in the same connection */
	conn->c_wsize = snprintf(conn->c_wbuf, DSERVER_TX_BUFLEN, "%s:%s", 
			((dlib_buffer_t *)(conn->c_data))->buffer, conn->c_rbuf);
	if (dserver_tcp_data_sendout(conn) < 0) {
		DLOG_ERR(LOG_PROT, "protocol_session_worker sending data error.");
		pipeline_data_cleanup(&pdata);
		dlib_buffer_exit((dlib_buffer_t *)(conn->c_data));
		conn->c_data = NULL;
		return PROTOCOL_ERROR;
	}

	pipeline_data_cleanup(&pdata);
	dlib_buffer_exit((dlib_buffer_t *)(conn->c_data));
	conn->c_data = NULL;

#ifdef DEF_TCP_CONTINUE
	return PROTOCOL_CONTINUE;
#elif defined (DEF_TCP_RESET)
	return PROTOCOL_RESET;
#else
	return PROTOCOL_CLOSE;
#endif
}

void protocol_session_exit(void *arg)
{
	DLOG_DEBUG(LOG_PROT, "PROTOCOL(TCP): protocol_session_exit.");

	if (arg == NULL) {
		DLOG_ERR(LOG_PROT, "protocol_session_init parameters error.");
		return;
	}

	dserver_conn_t *conn = (dserver_conn_t *)arg;
	prot_node_t *prot = conn->c_prot_node;
	char client_ip[INET_ADDRSTRLEN] = {0};

	ipv4_to_str(((struct sockaddr_in *)(&conn->c_csa))->sin_addr.s_addr, client_ip);
	DLOG_INFO(LOG_PROT, "session_exit: load data: %s | client info: %s",
			(char *)prot->p_data, client_ip);

	return;
}

void protocol_on_unload(prot_node_t *prot)
{
	DLOG_DEBUG(LOG_PROT, "PROTOCOL(TCP): protocol_on_unload.");

	if (prot == NULL) {
		return;
	}
	if (prot->p_data != NULL) {
		dfree(prot->p_data);
		prot->p_data = NULL;
	}
	return;
}
